package com.xneure.code.upload;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.xneure.utils.JsonUtil;
import com.xneure.utils.ObjectUtil;
import com.xneure.utils.SpringUtil;

@RestController
@RequestMapping("/file")
public class FileUpload_Download{
	@RequestMapping(value = "/upload")
	public void upload(HttpServletRequest request,HttpServletResponse response) throws IOException{
		response.setCharacterEncoding("charset=utf-8");
		response.setContentType("text/text;charset=utf-8");
		PrintWriter writer = response.getWriter();
		UploadMsg msg = new UploadMsg();
		try{
			FileUploadParam param = parseParam(request.getParameterMap());
			msg.setFileSize(param.getSize());
			UploadFileHandie fHandie = getFileHandie(param.getHandieID());
			InputStream iStream = convertStream(request.getInputStream(),request.getContentLength(),request.getContentType());
			fHandie.initParam(param);
			fHandie.checkType();
			fHandie.checkSize();
			fHandie.checkPath();
			File sFile = fHandie.checkFile();
			if(iStream == null){
				writeData(writer,msg.setSucceed(true).setReceiveSize(sFile.length()));
				return;
			}
			sFile = fHandie.saveFile(iStream,sFile);
			writeData(writer,msg.setSucceed(true).setParam(fHandie.returnParam()).setReceiveSize(sFile.length()));
		}catch(Exception e){
			if(e.getClass() == FileCheckException.class){
				writeData(writer,msg.setMsg(e.getMessage()));
			}else{
				writeData(writer,msg.setMsg("上传文件时发生错误。" + (null == e.getCause() ? e.getMessage() : e.getCause().getMessage())));
			}
		}
	}

	@RequestMapping(value = "/download")
	public void download(HttpServletRequest request,HttpServletResponse response) throws IOException{
		response.setCharacterEncoding("charset=utf-8");
		FileUploadParam param = parseParam(request.getParameterMap());
		UploadMsg msg = new UploadMsg();
		try{
			UploadFileHandie fHandie = getFileHandie(param.getHandieID());
			fHandie.initParam(param);
			fHandie.checkType();
			fHandie.checkPath();
			ServletOutputStream outputStream = response.getOutputStream();
			fHandie.setDownloadType(response);
			response.addHeader("Content-Disposition","attachment; filename=" + encodeData(request,param.getFileName()));
			fHandie.downloadFile(outputStream);
		}catch(Exception e){
			PrintWriter writer = response.getWriter();
			response.setHeader("Content-Disposition","text/text");
			if(e.getClass() == FileCheckException.class){
				writeData(writer,msg.setMsg(e.getMessage()));
			}else{
				writeData(writer,msg.setMsg("下载文件时发生错误。" + (null == e.getCause() ? e.getMessage() : e.getCause().getMessage())));
			}
		}
	}

	private String encodeData(HttpServletRequest request,String fileName) throws UnsupportedEncodingException{
		String agent = request.getHeader("USER-AGENT");
		if(null != agent && -1 != agent.indexOf("Firefox")){
			fileName = new String(fileName.getBytes("UTF-8"),"iso-8859-1");
		}else{
			fileName = java.net.URLEncoder.encode(fileName,"UTF-8");
		}
		return fileName;
	}

	private UploadFileHandie getFileHandie(String className){
		UploadFileHandie fHandie;
		if(ObjectUtil.isNull(className)){
			fHandie = SpringUtil.getBean(className);
		}else{
			fHandie = ObjectUtil.newInstance(className);
		}
		if(null == fHandie){
			throw new FileCheckException("处理器：".concat(className).concat(" 未注册。"));
		}else{
			return fHandie;
		}
	}

	/*
	 * 转换上传文件流对象
	 */
	private InputStream convertStream(InputStream inputStream,int length,String string){
		try{
			if(null == inputStream)
				return null;
			if(null == string || string.trim().length() < 1){
				BufferedInputStream bis = new BufferedInputStream(inputStream);
				byte[] b = new byte[10];
				bis.mark(b.length);
				if(bis.read(b) != -1){
					bis.reset();
					bis.mark(0);
					return bis;
				}
			}else{
				return readStreamFile(inputStream,length);
			}
			return null;
		}catch(Exception e){
			return null;
		}
	}

	private InputStream readStreamFile(InputStream inputStream,int length){
		int sPoint = 0, ePoint = 0;
		try{
			ByteArrayOutputStream os = new ByteArrayOutputStream(length);
			int rLength = 0;
			byte[] b = new byte[1024 * 1024 * 10];
			while((rLength = inputStream.read(b)) != -1){
				os.write(b,0,rLength);
			}
			byte[] byteArray = os.toByteArray();
			os.close();
			os = null;
			if(byteArray.length > 0){
				int point = arraySearch(1,byteArray,"name=".getBytes());
				if(point > -1){
					sPoint = arraySearch(point,byteArray,"\r\n\r\n".getBytes());
				}else{
					return null;
				}
				ePoint = byteArray.length;
				int j = ePoint - 100;
				if(j < 0){
					j = ePoint;
				}
				for(int i = byteArray.length - 5;i > j;i--){
					if(byteArray[i] == 45 && byteArray[i - 1] == 45){
						ePoint = i - 3;
					}
				}
			}
			byte[] tb = Arrays.copyOfRange(byteArray,sPoint + 1,ePoint);
			ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(tb);
			return byteArrayInputStream;
		}catch(IOException e){
			e.printStackTrace();
			return null;
		}
	}

	private static int arraySearch(int index,byte[] src,byte[] b){
		int sl = src.length;
		int bl = b.length;
		int i = index;
		for(;i < sl;i++){
			int j = 0;
			for(;j < bl;j++){
				if(src[i + j] != b[j]){
					break;
				}
			}
			i += j;
			if(j == bl){
				return i - 1;
			}
		}
		return -1;
	}

	private void writeData(PrintWriter writer,Object object){
		writer.write(JsonUtil.toJson(object));
		writer.flush();
	}

	// 解析URL中的参数
	@SuppressWarnings({"rawtypes","unchecked"})
	private FileUploadParam parseParam(Map param) throws UnsupportedEncodingException{
		FileUploadParam par = new FileUploadParam();
		for(Entry<String,String[]> entry:(new HashMap<String,String[]>(param)).entrySet()){
			String key = entry.getKey();
			if(key.equals("verifyCode")){
				par.setVerifyCode(entry.getValue()[0]);
			}else if(key.equals("handieID")){
				par.setHandieID(entry.getValue()[0]);
			}else{
				par.addParam(decode(key),decode(entry.getValue()[0]));
			}
		}
		return par;
	}

	private String decode(String val) throws UnsupportedEncodingException{
		return URLDecoder.decode(val,"utf-8");
	}
}
